/*
 * array.cpp
 *
 *  Created on: 09.11.2009
 *      Author: chris
 */

#include "../include/array.h"

vector<string> oal::array::itemsBuilding;

/**
 * Create an new array
 */
oal::array::array() {
//	cout << "CREATE Object " << this << endl;
	this->positionIteratorLoaded = false;
	this->value = "";
	this->items.clear();
	// this->itemsBuilding.clear();
	this->empty = true;
}

oal::array::array(string first) {
	// TODO Add function for array instance with start key
}
oal::array::array(string first, string second) {
	// TODO Add function for array instance with start key and value
}
oal::array::array(string first, array second) {
	// TODO Add function for array instance with start key and value array
}

/**
 * Destroy the full array with the function destroy();
 */
oal::array::~array() {
//	cout << "DELETE Object " << this << endl;
	this->destroy();
}

bool oal::array::searchForObjectToDelete(string data) {
bool result = false;

for(int i=0;i<(int)itemsBuilding.size();++i) {
//	cout << "TEST1 " << itemsBuilding[i] << " " << data << endl;
	if(itemsBuilding[i] == data) {
		result = true;
		itemsBuilding.erase(itemsBuilding.begin()+i);
		break;
	}
}
for(int i=0;i<(int)itemsBuilding.size();++i) {
//	cout << "TEST2 " << itemsBuilding[i] << " " << data << endl;
}
return result;
}

/**
 *	Gets the value of an given string
 *
 *	@param	string	string to get the value
 *
 *	@return	string	value of the given string
 *
 *	@todo	this function is not ready because the overloading
 *			don't work
 */
/*
string & oal::array::operator[] (char *data) const {
	return items[data]->value;
}
*/

/**
 * Destroyed the array and clean up all memorys
 */
void oal::array::destroy(void) {
//	cout << "DESTROY Object " << this << endl;
	if(this->empty == false) {
		map<string, array* >::iterator iter;

		for(iter = items.begin();
			iter != items.end();
			++iter
		) {
			stringstream ss;
//			ss << iter->second;
			if(iter->second) {
//				if(this->searchForObjectToDelete(ss.str())) {
//					for(int i=0;i<(int)itemsBuilding.size();++i) {
//						cout << "HAVE2 " << itemsBuilding[i] << " " << itemsBuilding.size() << endl;
//					}

/*				char *buffer;
					sprintf(buffer,"%p",iter->second);
					string iterSecondAddress(buffer);*/
//					cout << "Start array delete " << endl; // itemsBuilding[ss.str().c_str()] << " " << iter->second << endl;
	//				itemsBuilding[ss.str().c_str()] = false;
					delete iter->second;
//					cout << "Stop" << endl;

					for(int i=0;i<(int)itemsBuilding.size();++i) {
						cout << "TEST2 " << itemsBuilding[i] << " "  << endl;
					}
					iter->second = 0;
				}
//			}
		}
		items.clear();
		itemsSetup.clear();
//		itemsBuilding.clear();
		value.clear();
		this->empty = true;
	}
}

/**
 * Adds an new element to the array with the [] operator.
 * You can easy setup an new value with array[key] = value
 *
 * @param	string	key to get array to fill
 *
 * @return	array	array to set value
 */
oal::array & oal::array::operator[] (string data) {
	if(itemsSetup[data] == true) {
		return (*items[data]);
	} else {

//		map<const char*, bool >::iterator iter;
/*
		for(iter = itemsBuilding.begin();
			iter != itemsBuilding.end();
			++iter
		) {
			cout << "HAVE " << iter->first << endl;
		}*/
//		for(int i=0;i<(int)itemsBuilding.size();++i) {
//			cout << "HAVE2 " << itemsBuilding[i] << " " << itemsBuilding.size() << endl;
//		}
		items[data] = new array();
		itemsSetup[data] = true;
		// char *buffer;
		// sprintf(buffer,"%p",items[data]);
		// string iterSecondAddress(buffer);
		stringstream ss;
		ss << items[data];
		// itemsBuilding.push_back("OK");
//		itemsBuilding.push_back(ss.str());
//		cout << "ADD " << ss.str() << endl;
		this->empty = false;
		return (*items[data]);
	}
	return (*items[data]);
}

/**
 * Sets an value to the current array object
 *
 * @param	string	data to set
 */
void oal::array::operator= (string data){
	this->empty = false;
	this->value = data;
}

/**
 * Copy operator to setup one new array
 *
 * @param	array	array to copy to this array
 *
 * @return	array	this array object
 */
oal::array & oal::array::operator= (oal::array *data) {
	this->value = data->value;
	return (*this);
}

/**
 * Copy operator to copy complete arrays recusive
 *
 * @param	array	array to copy to this array
 *
 * @return	array	this array object
 */
oal::array & oal::array::operator= (const oal::array & data) {

	map<string, array* >::iterator iter;
	for(iter = data.items.begin();
		iter != data.items.end();
		++iter
	) {
		this->empty = false;
		(*this)[iter->first] = iter->second;
	}

	return *this;
}

/**
 * Checks if the current value to set
 *
 * @return	bool	false if empty, true otherwise
 */
bool oal::array::isEmpty(void) {
	return (this->empty);
}

/**
 * Sets the iterator to begin() and sets the variable
 * positionIteratorLoaded to true so it loaded only one time
 */
void oal::array::setupIterator(void) {
	if(this->positionIteratorLoaded == false) {
		positionIterator = this->items.begin();
		this->positionIteratorLoaded = true;
	}
}

/**
 * Setup the iterator and go to the next element
 */
bool oal::array::next(void) {
bool result = false;
	this->setupIterator();
	this->positionIterator++;
	if(positionIterator != this->items.end()) {
		result = true;
	}
	return result;
}

/**
 * Gets the key of the current array object
 *
 * @return	string	key of the array object
 */
string oal::array::key(void) {
string result="";
	this->setupIterator();
	if(positionIterator != this->items.end()) {
		result = positionIterator->first;
	}
return result;
}

/**
 * Gets the value of the current array
 *
 * @return	string	value of the current array
 */
string oal::array::get(void) {
string result="";
	if(items.size() > 1) {
		result ="Array";
	} else {
		result = this->value;
	}
	return result;
}

/**
 * Sends all entrys of the current array to stdout
 *
 * @param	string	tabLevel to setup tabs, can be empty
 */
void oal::array::debug(string tabs) {
		map<string, array* >::iterator iter;
		for(iter = items.begin();
			iter != items.end();
			++iter
		) {
			cout <<  tabs + "["+iter->first+"]";
			if(iter->second->items.size() > 0) {
				cout << " = array()\n";
				iter->second->debug(tabs + "\t");
			} else {
				cout <<  " = "+iter->second->get() << endl;
			}
		}
}


/**
 * Seri an array to an string like php function serialise
 *
 * @return	string	 array as string
 */
string oal::array::toString(void) {
string result = (string)"a:" + intToStr(items.size()) + ":{";
	map<string, array* >::iterator iter;
	for(iter = items.begin();
		iter != items.end();
		++iter
	) {
		result += "s:"+intToStr(iter->first.length())+":\""+iter->first+"\";";
		if(iter->second->items.size() > 0) {
			result += iter->second->toString();
		} else {
			result += "s:"+intToStr(iter->second->get().length())+":\""+iter->second->get()+"\";";
		}
	}
	return result + "}";
}

/**
 * Get the position of the ; string to get single values.
 * if a bracket char { found than cut to the given }
 * All values escaped by " will be ignored
 *
 * @param	string	data to search for
 *
 * @return	int		position of the first ; Char
 */
int oal::array::getEndPosition(string data) {
int result = -1;
int counter = 0;
bool start=false;
for(int i=0;i<(int)data.length();++i) {
	if(data[i] == '"') {
		int next = data.find("\"", i);
		if(next > -1) {
			i = next;
		}
	}

	if(data[i] == '{') {
		counter++;
		start=true;
	}
	if(data[i] == '}') {
		counter--;
		if(counter <= 0) {
			result = i;
			break;
		}
	}

	if(data[i] == ';' && counter==0) {
		result = i;
		break;
	}
}
return result;
}

/**
 * Get an string escaped by ""
 *
 * @param	string	escaped value
 * @return	string	unescaped value
 */
string oal::array::getValueString(string data) {
string result ="";
	int pos1 = data.find("\"")+1;
	int pos2 = data.find("\"", pos1);
	if(pos1 > -1 && pos2 > -1) {
		result = data.substr(pos1, pos2 - pos1);
	}
return result;
}

/**
 * Get only the value and substr 2 bytes in front
 * of the string
 *
 * @param	string	value
 *
 * @return	string	new value
 */
string oal::array::getValueInteger(string data) {
string result = data.substr(2);
return result;
}

/**
 * Get an array from an given string like serialize in PHP
 *
 * @param	string	data to add to the current array
 */
void oal::array::fromString(string data) {
	if(!data.empty()) {
		if(data[0] == 'a') {
			int firstPosition = data.find("{")+1;
			int lastPos = data.rfind("}");
			(*this).fromString(
				data.substr(firstPosition,lastPos - firstPosition)
			);
		} else {
			int endPos=0;
			while(endPos > -1) {
				// Get the end Position of the key part
				endPos = this->getEndPosition(data);
				if(endPos == -1) {
					break;
				}
				string key = this->getValueString(data.substr(0,endPos));

				// Delete Key Part
				data = data.substr(endPos+1);

				// Get the end Position of the value part
				endPos = this->getEndPosition(data);
				string value = data.substr(0,endPos);

				// Add Values
				if(value[0] == 'a') {
					(*this)[key].fromString(value);
				}
				if(value[0] == 's') {
					(*this)[key] = this->getValueString(value);
				}
				if(value[0] == 'i') {
					(*this)[key] = this->getValueInteger(value);
				}

				if((int)data.length() <= endPos) {
					data="";
					break;
				}
				data = data.substr(endPos+1);
			}
		}
	}
}
